home *** CD-ROM | disk | FTP | other *** search
- main group code
- code segment public para 'code'
- assume cs:main
-
- org 100h ;.COM file
-
- BEGIN: jmp START ;program starts here
- db "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
- signature db 'PUSHDIR VERSION 1.0'
- lengthsignature = $ - signature
-
- savedint16 dd ? ;old int 16h vector
-
- nextpush dw offset main:push1dir ;next place to save a dir
- push1dir db 67 dup (0) ;storage for a saved dir
- push2dir db 67 dup (0) ;more storage
- push3dir db 67 dup (0) ;more storage
- push4dir db 67 dup (0) ;more storage
- push5dir db 67 dup (0) ;more storage
- push6dir db 67 dup (0) ;last storage
-
- ;up to here must be EXACTLY identical in both PUSHDIR and POPDIR so that
- ;popdir can know how to access the memory space reserved by the first
- ;pushdir.
-
- ;myint16 is an interrupt handler chained onto the existing interrupt handler.
- ;it is used to find out if PUSHDIR is already installed and if it is, where
- ;is it located? It works by adding another function to int 16h. To use it
- ;ax = 7788h, bx = 7789h, and ds:si points to the signature string. If any one
- ;of these conditions is not true, then the int 16h call is passed onto the
- ;old routine without doing anything. If they are all true, then we switch
- ;ax and bx and return ds = code segment (cs) of the interrupt handler.
-
- myint16 proc far
-
- pushf ;save flags
- cmp ax,7788h ;possible signature request ?
- je CHECKSIG ;yes
- NOTSIG:
- popf ;no - recover flags
- jmp cs:[savedint16] ;go to old routine as normal
-
- CHECKSIG:
- cmp bx,7789h ;possible signature request ?
- jne NOTSIG ;no
-
- ;ax and bx were correct for a signature request
- ;now see if ds:si was pointing to the signature string
- ;the whole idea of the signature is that is has to be
- ;totally unique so no other program could possibly use the same one.
-
- push es ;save the registers we will use
- push di
- push cx
- mov di,offset main:signature ;address of the signature
- mov cx,lengthsignature ;length of the signature
- repe cmpsb ;does string at ds:si match es:di ?
- pop cx ;recover all registers we used
- pop di
- pop es
- jne NOTSIG ;no, not correct signature
-
- ;yes, it was a signature request so return ds equal to the current code
- ;segment so subsequent pushdir's and popdir's know where the original
- ;is located.
-
- push cs
- pop ds ;set ds = cs
- xchg ax,bx ;flip these two so we know that
- ;ds is being returned
- popf ;recover original flags
- iret ;return back to the program
- ;that called the int 16h
-
- myint16 endp
-
- endresident label byte ;label marking the end of the
- ;code to remain resident
-
- ;code after here will not remain resident
-
- install db 1 ;0 = already installed, 1 = not installed
-
- abortmsg db 'Error reading the current directory.$'
- installmsg db 'PUSHDIR installed.$'
-
- START:
- sti ;turn interrupts on
-
- ;first check to see if PUSHDIR is already installed
-
- mov ax,7788h ;signature request
- mov bx,7789h ;signature request
- mov si,offset main:signature ;point to signature
- int 16h ;is it installed ?
-
- assume ds:nothing
-
- cmp bx,7788h ;were ax and bx switched ?
- jne NOTINSTALLED ;no
- cmp ax,7789h ;were ax and bx switched ?
- jne NOTINSTALLED ;no
-
- ;yes it is installed already
-
- mov cs:[install],0 ;don't install it again
- NOTINSTALLED:
-
- ;ds = segment of the installation
-
- ;store the current directory, including disk drive letter
-
- mov si,ds:[nextpush] ;get storage address for next push
- add si,3 ;make room for d:\
- mov dl,0 ;default drive
- mov ah,47h ;dos function number
- int 21h ;get current directory
- jc ABORTERR ;error message if carry set
- mov ah,19h ;dos function number
- int 21h ;get the current drive
- add al,'A' ;convert to ascii
- mov byte ptr ds:[si-3],al ;add the "D:\" in front of path
- mov byte ptr ds:[si-2],':'
- mov byte ptr ds:[si-1],'\'
-
- ;now update [nextpush] for the next PUSHDIR
-
- cmp ds:[nextpush],offset main:push6dir ;time to wrap around ?
- je WRAPPUSH ;yes
- add ds:[nextpush],67 ;no, point to next one
- jmp short GOTNEXTPUSH
- WRAPPUSH:
- mov ds:[nextpush],offset main:push1dir ;wrap back to beginning
- GOTNEXTPUSH:
- cmp cs:[install],1 ;should we install it
- je DOINSTALL ;yes
- int 20h ;no, we are done
-
- ABORTERR:
- mov dx,offset main:abortmsg ;address of error message
- mov ah,9 ;dos function number
- int 21h ;show error message
- int 20h ;end program on error
-
-
- ;if we got to here, then pushdir is not already installed,
- ;so we need to install it by making part of it memory resident.
-
- DOINSTALL:
- push cs
- pop ds ;set ds = cs
-
- assume ds:main
-
- ;save the current int 16h vector
-
- push es ;save es
- mov ax,3516h ;dos function 35h, vector 16h
- int 21h ;get the existing vector into es:bx
- mov word ptr [savedint16],bx ;save es:bx
- mov word ptr [savedint16+2],es ;save es:bx
- pop es ;recover es
-
- ;now set the new int 16h vector to point to my routine
-
- mov dx,offset main:myint16 ;point to my new routine
- mov ax,2516h ;dos function 25h, vector 16h
- int 21h ;set new vector to ds:dx
-
- ;now show a message on the screen
- ;this message can be suppressed by redirecting output to NUL
- ;by using pushdir like this: PUSHDIR >NUL
-
- mov dx,offset main:installmsg
- mov ah,9
- int 21h ;show installation message
-
- ;now free up the memory occupied by the envirnoment so it is not
- ;permanently wasted
-
- mov ax,ds:[2ch] ;get segment of environment
- mov es,ax ;load envirnoment segment into es
- mov ah,49h ;dos function number
- int 21h ;free the environment memory
-
- ;now terminate resident protecting only the first part of this program
-
- mov dx,offset main:endresident ;point to end of resident code
- add dx,0fh ;round up
- mov cl,4
- shr dx,cl ;convert to paragraphs (divide by 16)
- mov ax,3100h ;dos function 31h, error code=0
- int 21h ;terminate and remain resident
-
- code ends
- end begin ;start execution at BEGIN
-